#ifndef __MESH_C_H__
#define __MESH_C_H__
//用来管理依赖于网格的并行数据通讯，也就是说这里的通讯都是以网格的并行信息为基础的
//用户只需要在自己自己进程中相应的网格几何元素上进行定义数据，本文件中的程序就可以自动对所定义的
//数据进行通讯
#include "mesh.h"
#include "constants.h"

#if MPI_USE

typedef struct ATTACHED_DATA_PRIVATE_
{
    INT BlockSize;     //表示每个几何对象上对应的Data的大小
    MPI_Datatype Dttp; // MPI中的数据类型
    void *Data;        //具体的数据
} ATTACHED_DATA_PRIVATE;
typedef ATTACHED_DATA_PRIVATE *ATTACHEDDATA;

typedef struct GEOBRIDGE_
{
    INT VertNum;
    INT *VertIndex;
    INT LineNum;
    INT *LineIndex;
    INT FaceNum;
    INT *FaceIndex;
    INT VoluNum;
    INT *VoluIndex;
}GEOBRIDGE;

typedef struct BRIDGE_
{
    INT worlddim;

    INT DestinationRankNum;
    INT *DestinationRank;
    GEOBRIDGE *GeoSend;

    INT OriginRankNum;
    INT *OriginRank;
    GEOBRIDGE *GeoRecv;

    INT oldgeonum[4];
    INT newgeonum[4];
    MPI_Comm pure_comm;
    MPI_Comm BridgeComm;
}BRIDGE;

typedef struct PARDATA_PRIVATE_
{
    INT worlddim;
    /*parmesh的并行信息*/
    MESH *mesh;
    BRIDGE *bridge;
    SHAREDGEO **customsharedinfo;
    /* 存储依附在并行几何元素上的并行数据*/
    INT NumDatas[5];        //记录点、线、面、体各自有多少个数据块
    ATTACHEDDATA *VertData; //依附在点上的数据
    ATTACHEDDATA *LineData; //依附在线上的数据
    ATTACHEDDATA *FaceData; //依附在面上的数据
    ATTACHEDDATA *VoluData; //依附在体上的数据
    ATTACHEDDATA *SubDomianData;
    INT CustomNum;                                                                         
    ATTACHEDDATA *CustomData; //自定义的
} PARADATA;

typedef struct RECEIVE_DATA_
{
    INT NumTypes[5];   //记录接收到数据的种类数, 五个位置分别表示点、线、面、体和进程上的数据种类数
    INT VertNum;       //从所有进程上收到的节点信息份数, 会出现一个节点对应多个进程的情况, 每个进程都有一份
    INT *VertIndex;    //接收到每份数据所在的节点在本进程中的局部编号
    void **VertDatas;  //具体数据:NumType[0]长度, 每个元素指向一种数据: 第一重指针对应所有VertIndex第几种类型的数据, 第二重指针表示每个VertIndex上的具体数据
    INT LineNum;
    INT *LineIndex;
    void **LineDatas;
    INT FaceNum;
    INT *FaceIndex;
    void **FaceDatas;
    INT VoluNum;
    INT *VoluIndex;
    void **VoluDatas;
    void **SubDomianData;
    INT CustomNum;
    INT *CustomDataNum;
    INT **CustomDataIndex;
    void **CustomData;
} RECDATA;

/* creation */
void ParaDataCreate(PARADATA **ParaData, MESH *mesh);
void AttachedDataCreate(ATTACHEDDATA *AttachedData, INT BlockSize, MPI_Datatype Dttp, void *Data);
void RecDataCreate(PARADATA *ParaData, RECDATA **RecData);
void BridgeCreate(BRIDGE **bridge, INT worlddim);
void SendGeoBridgeCreate(BRIDGE *bridge, INT num);
void RecvGeoBridgeCreate(BRIDGE *bridge, INT num);
void ParaDataCreateWithBridge(PARADATA **ParaData, BRIDGE *bridge);
void ParaDataCreateByParaData(PARADATA **ParaData, PARADATA *Sample);

/* operation */
void BridgeReverse(BRIDGE *bridge);

/* communicator */
void NeighborCommCreate(MESH *mesh);
void BridgeCommCreate(MESH *newmesh, MESH *oldmesh, BRIDGE *bridge);

/* data */
// geotype:0点1线2面3体4网格本身
void ParaDataAdd(PARADATA *ParaData, INT geotype, INT BlockSize, MPI_Datatype Dttp, void *Data);
void ParaDataAddCustomData(PARADATA *ParaData, SHAREDGEO *sharedinfo, INT BlockSize, MPI_Datatype Dttp, void *Data);
void ParaDataSynchronize(PARADATA *ParaData, RECDATA **RecData);
void SynRecDataCreate(PARADATA *ParaData, RECDATA **RecData);
INT SynRecPackageSize(PARADATA *ParaData, SHAREDINFO *SharedInfo, INT neigind);
void ParaDataSynchronize(PARADATA *ParaData, RECDATA **RecData);
void ParaDataSub(PARADATA *ParaData, INT geotype); //清除某种数据
void ParaDataClean(PARADATA *ParaData);            //清除所有数据
void RecDataDestroy(RECDATA **RecData);
void ParaDataDestroy(PARADATA **ParaData);
void BridgeDestroy(BRIDGE **bridge);

/* print */
void ParaDataPrint(PARADATA *ParaData);
void BridgePrint(BRIDGE *bridge, INT rank);

/* communication */
void ParaDataCommunicate(PARADATA *ParaData, RECDATA **RecData);
INT PackageSize(PARADATA *ParaData, SHAREDINFO *SharedInfo, INT neigind);
INT SynPackageSize(PARADATA *ParaData, SHAREDINFO *SharedInfo, INT neigind);
void SynPackageData(PARADATA *ParaData, SHAREDINFO *SharedInfo, INT neigind, char *package, INT size, INT *position);
void SynUnpackage(PARADATA *ParaData, RECDATA *RecData, char *package, INT totalsize, INT *size, INT *displs, INT packagenum);
void PackageData(PARADATA *ParaData, SHAREDINFO *SharedInfo, INT neigind, char *package, INT size, INT *position);
void Unpackage(PARADATA *ParaData, RECDATA *RecData, char *package, INT totalsize, INT *size, INT *displs, INT num);
void BridgeCommunicate(PARADATA *SendParaData, PARADATA *RecvParaData);
INT BridgePackageSize(PARADATA *ParaData, INT neigind);
INT BridgeBoxSize(PARADATA *ParaData, INT neigind);
void BridgePackageData(PARADATA *ParaData, INT neigind, char *package, INT size, INT *position);
void BridgeUnpackage(PARADATA *SendParaData, PARADATA *RecvParaData, char *package, INT totalsize, INT *size, INT *displs, INT num);


#endif

#endif